﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using iTextSharp.text;
using iTextSharp.text.pdf;

namespace iPdf
{

    class PdfPageRearranger
    {
        #region Methods

        private static string GetPageString(Hashtable map, Hashtable destinations)
        {
            string page = (string)map["Page"];
            string named = (string)map["Named"];
            if (page == null && named != null)
            {
                page = (string)destinations[named];
            }

            return page;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.Parse(System.String)")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.Parse(System.String)")]
        private static int GetPageNo(ref string page)
        {
            int pageNo = 0;
            if (page != null)
            {
                page = page.Trim();
                int idx = page.IndexOf(' ');
                if (idx < 0)
                {
                    pageNo = int.Parse(page);
                }
                else
                {
                    pageNo = int.Parse(page.Substring(0, idx));
                    page = page.Substring(idx);
                }
            }

            return pageNo;
        }

        private static bool CheckHit(Hashtable map, Hashtable destinations, 
                                                                int from, int to)
        {
            bool hit = true;
            int pageNo = 0;
            if ("GoTo".Equals(map["Action"]))
            {
                string page = GetPageString(map, destinations);

                if (page != null)
                {
                    pageNo = GetPageNo(ref page);
                    if (pageNo < from || pageNo > to)
                    {
                        hit = false;
                    }
                }
            }

            return hit;
        }

        public static Hashtable GetNamedDestinations(PdfReader reader)
        {
            Hashtable PdfNameDestinations = SimpleNamedDestination.GetNamedDestination(reader, false);
            Hashtable PdfStringDestinations = SimpleNamedDestination.GetNamedDestination(reader, true);
            foreach (DictionaryEntry entry in PdfStringDestinations)
            {
                PdfNameDestinations.Add(entry.Key, entry.Value);
            }

            return PdfNameDestinations;
        }

        //refresh the node with the new page no
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString")]
        private static void ShiftBookmarkNode(ref Hashtable node, Hashtable destinations, int shiftOffset)
        {
            string page = GetPageString(node, destinations);
            int pageNo = GetPageNo(ref page);
            if(pageNo != 0)
            {
                pageNo += shiftOffset;
                node["Page"] = pageNo.ToString() + page;
                node.Remove("Named");
            }
        }

        public static ArrayList ProcessBookmarks(ArrayList list, Hashtable destinations, 
                                                     int from, int to, int numOfPages, int shiftOffset)
        {
            if (list == null)
            {
                return null;
            }

            int adjustedCount = 0;
            int adjustedIndex;
            int eleCnt = list.Count;
            for (int i = 0; i < eleCnt; ++i)
            {
                adjustedIndex = i + adjustedCount;
                Hashtable map = (Hashtable)list[adjustedIndex];
                bool hit = CheckHit(map, destinations, from, to);

                ArrayList kids = (ArrayList)map["Kids"];
                if (kids != null)
                    map["Kids"] = ProcessBookmarks(kids, destinations, from, to, numOfPages, shiftOffset);
                if (hit == false)
                {
                    list.RemoveAt(adjustedIndex);
                    --adjustedCount;
                    if (kids != null && kids.Count > 0)
                    {
                        list.InsertRange(adjustedIndex, kids);
                        adjustedCount += kids.Count;
                    }
                }
                else
                {
                    //shift the page
                    ShiftBookmarkNode(ref map, destinations, shiftOffset);
                }
            }

            return list;
        }

        public static void AddPages(PdfReader reader, PdfCopy writer, string fileName)
        {
            AddPages(reader, writer, 1, reader.NumberOfPages, fileName);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public static void AddPages(PdfReader reader, PdfCopy writer, int from, int to, string fileName)
        {
            try
            {
                int offset = from <= to ? 1 : -1;
                for (int i = from - offset; i != to; i += offset)
                {
                    writer.AddPage(writer.GetImportedPage(reader, i+offset));
                }
            }
            finally
            {
                SharpHelper.ClosePdf(reader, null);
            }
        }

        #endregion
    }
}
